<?php

namespace App\Models;

use App\Events\UserRechargeEvent;
use App\Events\UserWithdrawEvent;
use App\Handlers\KeysHandler;
use Carbon\Carbon;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class Order extends Model
{
    use HasDateTimeFormatter;

    // 订单类型
    const ORDER_TYPE = [
        0 => '提现',
        1 => '充值'
    ];

    const WITHDRAWAL = 0;//提现
    const RECHARGE = 1;//充值

    const REVIEW = -1;  // 审核
    const PENDING = 0;   // 进行中
    const SUCCESS = 1;   // 成功
    const FAILED = 2;   // 失败
    const CANCEL = 3;   // 取消
    const REFUSE = 4;   // 拒绝

    const STATE_MAP = [
        self::REVIEW => '待审核',
        self::PENDING => '进行中',
        self::SUCCESS => '成功',
        self::FAILED => '失败',
        self::CANCEL => '取消',
        self::REFUSE => '拒绝'
    ];

    protected $fillable = [
        'user_id', 'platform', 'payment_third_pay_id', 'amount', 'withdrawal_fee', 'handling_fee', '', 'actual_amount', 'no', 'payment_no', 'paid_at', 'closed', 'type', 'state', 'card', 'param', 'response', 'notify_response', 'remark'
    ];


    // 明细
    public function account()
    {
        return $this->hasOne(Account::class);
    }

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function payment_third_pay()
    {
        return $this->belongsTo(PaymentThirdPay::class);
    }

    public function payment_third_code_recharge()
    {
        return $this->belongsTo(PaymentThirdCode::class,'payment_third_pay_id','id')->with('payment');
    }

    public function userHierarchyDefault()
    {
        return $this->belongsTo(User::class,'user_id','id')->where('hierarchy_id','=',1);
    }

    public function orderDoc()
    {
        return $this->hasOne(OrderDocs::class);
    }

    //类型作用域
    public function scopeType(Builder $query, $type)
    {
        return $query->where('type', '=', $type);
    }

    //收款地址
    public function rechargeAddress(): BelongsTo
    {
        return $this->belongsTo(RechargeAddress::class, 'payment_third_pay_id');
    }

    /**
     * 完成支付
     * @param $state
     * @param $no
     * @param $paymentNo
     * @param $paidAt
     * @param $response
     * @return mixed
     */
    public function rechargeComplete($state, $no, $paymentNo, $paidAt, $response): bool
    {
        return DB::transaction(function () use ($state, $no, $paymentNo, $paidAt, $response) {
            $order = self::query()->where('no', '=', $no)
                ->where('closed', '=', 0)
                ->lockForUpdate()
                ->first();
            // 关闭订单
            $order->state = $state;
            $order->paid_at = $paidAt;
            $order->closed = 1;
            $order->payment_no || $order->payment_no = $paymentNo;
            $order->notify_response = $response;
            $order->save();
            if ($state == self::SUCCESS) {
                $user = User::where('id', '=', $order->user_id)->first();
                $user->increment('balance', $order->amount);
                //$user->isrecharge = 1;
                $user->save();
                (new Account())->store($order->user_id, $order->amount, Account::RECHARGE, 0, $order->id);
                //充值赠送
                /*
                if($user->vip->recharge_gift_ratio != 0){
                    $gift_mount = bcmul(bcmul($order->amount, $user->vip->recharge_gift_ratio, 4) , 0.01 ,4);
                    $user->increment('balance', $gift_mount);
                    (new Account())->store($order->user_id, $gift_mount, Account::RECHARGE_GIFT, 0, $order->id);
                }
                app(User::class)->InvitationReward($user); //邀请奖励
                */
                //充值成功的事件
                //event(new UserRechargeEvent($order));
            }
            return true;
        });
    }

    /**
     * 创建提现订单
     * @param User $user
     * @param int $amount
     * @param Card $card
     * @return mixed
     */
    public function createWithdrawOrder(User $user, int $amount, Card $card)
    {
        return DB::transaction(function () use ($user, $amount, $card) {
            //银行卡信息
            $user = User::query()->where('id', '=', $user->id)->lockForUpdate()->first();
            return $this->withdraw($user, $amount, $card);
        });
    }


    /**
     * 提现
     * @param User $user 用户
     * @param int $amount 金额
     * @param Card $card 银行卡信息
     * @return int
     */
    public function withdraw(User $user, $amount, Card $card): int
    {
        if ($amount > $user->balance) {
            return 10016;
        }
        $withdrawal_fee = 0;
        //手续费
        $handling_fee = ceil(bcmul($amount, bcdiv($withdrawal_fee, 100, 2),2));
        //银行卡信息
        $order = $user->order()->create([
            'amount' => $amount,
            'withdrawal_fee' => $withdrawal_fee,
            'handling_fee' => $handling_fee,
            'actual_amount' => bcsub($amount, $handling_fee),
            'no' => only_code(),
            'type' => Order::WITHDRAWAL,
            'state' => Order::REVIEW,
            'card' => json_encode($card, JSON_UNESCAPED_UNICODE)
        ]);
        // 扣余额 加冻结
        $user->decrement('balance', $amount);
        $user->increment('freeze_balance', $amount);
        $account_amount = bcmul($amount, -1,);
        (new Account())->store($order->user_id, $account_amount, Account::WITHDRAWAL, 0, $order->id);
        $user->save();
        return 1;
    }

    /**
     * 获取列表数据
     * @param User $user
     * @param int $type
     * @param int $page
     * @param int $limit
     * @param string $date
     * @return Order[]|Builder[]|Collection
     */
    public function list(User $user, int $type, int $page, int $limit, string $date)
    {
        $model = self::query()->where('user_id', '=', $user->id);
        if ($date) {
            /*
            $model->whereBetween('created_at', [
                Carbon::parse($date)->firstOfMonth(),
                Carbon::parse($date)->lastOfMonth()->addDay(),
            ]);
            */
            $model->whereDate('created_at', '=', Carbon::parse($date));
        }
        return $model->where('type', '=', $type)
            ->select(['id', 'no', 'withdrawal_fee', 'handling_fee', 'amount', 'remark', 'type', 'state', 'created_at'])
            ->offset($page)
            ->limit($limit)
            ->latest()->get();
    }


    /**
     * 用户取消提现
     * @param int $order_id
     * @return bool
     */
    static public function withdrawCancel(int $order_id): bool
    {
        return DB::transaction(function () use ($order_id) {
            $order = self::query()->where('id', '=', $order_id)
                ->where('type', '=', self::WITHDRAWAL)
                ->where('state', '=', self::REVIEW)
                ->lockForUpdate()->first();
            if ($order) {
                $order->state = self::CANCEL;
                $order->closed = 1;  //关闭订单
                $order->remark = 'User canceled';  //默认备注
                $order->save();
                $user = User::where('id', '=', $order->user_id)->first();
                User::where('id', '=', $order->user_id)->decrement('freeze_balance', $order->amount);  // 减冻结
                User::where('id', '=', $order->user_id)->increment('balance', $order->amount);  // 加余额
                $user->save();
                (new Account())->store($order->user_id, $order->amount, Account::WITHDRAWAL_FAIL, 0, $order->id);
                return true;
            }
            return false;
        });
    }


    /**
     * 提现失败
     * @param $order
     * @return mixed
     */
    public static function withdrawFail($order)
    {
        self::returnUserMoney($order);
        //  第三方返回失败余额返还用户
        $order->state = Order::FAILED;
        $order->closed = 1;  //关闭订单
        $order->remark = 'Re-withdraw after checking bank card details';  //默认备注
        return $order;
    }

    //提现失败返还用户提现金额
    public static function returnUserMoney(Order $order)
    {
        $user = User::where('id', '=', $order->user_id)->first();
        User::where('id', '=', $order->user_id)->decrement('freeze_balance', $order->amount);  // 减冻结
        User::where('id', '=', $order->user_id)->increment('balance', $order->amount);  // 加余额
        $user->save();
        (new Account())->store($order->user_id, $order->amount, Account::WITHDRAWAL_FAIL, 0, $order->id);
    }

    /**
     * 完成提现
     * @param array $data 关键数据
     * @param array $param 回调参数
     * @return mixed
     */
    public function withdrawComplete(array $data, array $param)
    {
        return DB::transaction(function () use ($data, $param) {
            if (isset($data['paymentNo'])) {
                $order = $this->where('payment_no', '=', $data['paymentNo'])
                    ->where('no', '=', $data['orderId'])
                    ->lockForUpdate()
                    ->where('closed', '=', 0)
                    ->first();
            } else {
                $order = $this
                    ->where('no', '=', $data['orderId'])
                    ->where('closed', '=', 0)
                    ->lockForUpdate()
                    ->first();
            }

            if (!$order) {
                return false;
            }

            $order->state = $data['state'];
            $order->paid_at = $data['paidAt'];
            if ($data['state'] == self::SUCCESS) {
                $order->closed = 1;  //成功订单状态改为关闭,其它状态 不关闭
                // 减冻结
                User::where('id', '=', $order->user_id)->decrement('freeze_balance', $order->amount);
                $user = User::query()->where('id', '=', $order->user_id)->first();
                //$user->iswithdrawal = 1;
                $user->save();
                //提现成功的事件
                //event(new UserWithdrawEvent($order));
            } else {
                $order = self::withdrawFail($order);
            }
            $order->notify_response = json_encode($param, JSON_UNESCAPED_UNICODE);
            $order->save();
            return true;
        });
    }


    //通过订单id获取订单数据
    public static function getOrder(int $id)
    {
        $key = sprintf(KeysHandler::ORDER, $id);
        $order = Cache::get($key);
        if (!$order) {
            $order = self::query()->find($id);
            Cache::put($key, $order, KeysHandler::ORDER_TTL);
        }
        return $order;
    }


    //获取昨日提现
    public static function yesterdayWithdraw()
    {
        return Order::query()->where('type', '=', Order::WITHDRAWAL)
            ->where('state', '=', Order::SUCCESS)
            //->where('payment_third_pay_id', '<>', 0)
            ->whereDate('created_at', '=', \Illuminate\Support\Carbon::yesterday())
            ->sum('actual_amount') /100;

    }

    //今日提现
    public static function todayWithdraw()
    {
        return Order::query()
            ->where('type', '=', Order::WITHDRAWAL)
            ->where('state', '=', Order::SUCCESS)
            //->where('payment_third_pay_id', '<>', 0)
            ->whereDate('created_at', '=', now())
            ->sum('actual_amount') / 100;
    }

    //总提现
    public static function totalWithdraw()
    {
        return Order::query()->where('type', '=', Order::WITHDRAWAL)
            ->where('state', '=', Order::SUCCESS)
            //->where('payment_third_pay_id', '<>', 0)
            ->sum('actual_amount') / 100;
    }

    //昨日充值
    public static function yesterdayRecharge()
    {
        return Cache::remember(KeysHandler::YESTERDAY_RECHARGE, now()->endOfDay(), function () {
            return Order::query()
                ->where('type', '=', Order::RECHARGE)
                ->where('state', '=', Order::SUCCESS)
                ->whereDate('created_at', '=', \Illuminate\Support\Carbon::yesterday())
                ->sum('amount') / 100;
        });
    }


    //今日充值
    public static function todayRecharge()
    {
        return Order::query()
            ->where('type', '=', Order::RECHARGE)
            ->where('state', '=', Order::SUCCESS)
            ->whereDate('created_at', '=', now())
            ->sum('amount') / 100;
    }


    //总充值
    public static function totalRecharge()
    {
        return Order::query()->where('type', '=', Order::RECHARGE)
            ->where('state', '=', Order::SUCCESS)
            ->sum('amount') / 100;

    }

    //按日期充值人数
    public static function rechargeUserCount($date){
        return Order::query()->where('type', '=', Order::RECHARGE)
            ->where('state', '=', Order::SUCCESS)
            ->whereDate('created_at', '=', $date)
            ->groupby('user_id')->get()->count();
    }

    //按日期提现金额
    public static function withdrawalUserAmount($date){
        return Order::query()->where('type', '=', Order::WITHDRAWAL)
            ->where('state', '=', Order::SUCCESS)
            ->whereDate('created_at', '=', $date)
            ->sum('actual_amount');
    }

    //按日期提现人数
    public static function withdrawalUserCount($date){
        return Order::query()->where('type', '=', Order::WITHDRAWAL)
            ->where('state', '=', Order::SUCCESS)
            ->whereDate('created_at', '=', $date)
            ->groupby('user_id')->get()->count();
    }


    //按日期查今日复冲人数
    public static function secendRechargeUserCount($date){
        $key = sprintf('secendRechargeUserCount%s',$date->toDateString());
        if($date->lt(Carbon::yesterday())){
            $this_row = Cache::get($key);
            if($this_row){
                return $this_row;
            }
        }
        $this_row =   Order::query()
            ->select('user_id')
            //->whereHas('userHierarchyDefault')
            ->where('type', '=', Order::RECHARGE)
            ->where('state', '=', Order::SUCCESS)
            ->whereIn('user_id', function ($query) use ($date) {
                $query->select('user_id')->from('orders')
                    ->where('type', '=', Order::RECHARGE)
                    ->where('state', '=', Order::SUCCESS)
                    ->whereDate('created_at', '=', $date);
            })
            ->whereDate('created_at', '<', $date)
            ->groupby('user_id')
            //->havingRaw('count(*)>=1')
            ->get()
            ->count();
        if($date->lt(Carbon::yesterday())){
            Cache::put($key, $this_row, 60*60*24*7);
        }
        return $this_row;
    }

    //按日期充值人数--首存- 只存款了一次
    public static function rechargeFirstUserCount($date){
        $key = sprintf('rechargeFirstUserCount%s',$date->toDateString());
        if($date->lt(Carbon::yesterday())){
            $this_row = Cache::get($key);
            if($this_row){
                return $this_row;
            }
        }
        $this_row =  Order::query()->whereHas('userHierarchyDefault')
            //->select('user_id', DB::raw('count(*) as num'))
            ->where('type', '=', Order::RECHARGE)
            ->where('state', '=', Order::SUCCESS)
            ->whereIn('user_id', function ($query) use ($date) {
                $query->select('user_id')->from('orders')
                    ->where('type', '=', Order::RECHARGE)
                    ->where('state', '=', Order::SUCCESS)
                    ->whereDate('created_at', '=', $date);
            })
            ->whereDate('created_at', '<=', $date)
            //->where('num', '=', 1)
            ->groupby('user_id')
            ->havingRaw('count(*) = 1')
            ->get()->count();
        if($date->lt(Carbon::yesterday())){
            Cache::put($key, $this_row, 60*60*24*7);
        }
        return $this_row;
    }



}
